package indi.h.targetcall;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import indi.h.targetcall.calls.STCall;
import indi.h.targetcall.calls.TCall;
import indi.h.targetcall.calls.TCall.Reset;
import indi.h.targetcall.calls.TCall.Task;
import indi.h.targetcall.locks.DataConflictLock;
import indi.h.targetcall.manager.STManager;

public class STaskPool {
	private List<GenParDiff> tCallList;
	private TCall tCall;

	protected STaskPool() {
		// TODO Auto-generated constructor stub
		tCallList = new ArrayList<GenParDiff>();
	}

	public static <T, E> STaskPool getSTaskPool(Class<T> id, Class<E> target, TCall<T, E> tCall) {
		return Single.TARGET.createOrGet(id, target, tCall);
	}

	public static <T, E> STaskPool getSTaskPool(Class<T> id, Class<E> target) {
		return getSTaskPool(id, target, new STCall<T, E>(new STManager<T, E>(), new DataConflictLock<T>()));
	}

	private static enum Single {
		TARGET;
		private volatile STaskPool sTaskProcessors;
		private ReentrantLock rl;

		Single() {
			sTaskProcessors = new STaskPool();
			rl = new ReentrantLock();
		}

		public <T, E> STaskPool createOrGet(Class<T> id, Class<E> target, TCall<T, E> tCall) {
			final ReentrantLock r = rl;
			try {
				r.lock();
				if (id == null)
					throw new NullPointerException("id must need");
				if (target == null)
					throw new NullPointerException("target must need");
				if (tCall == null)
					throw new NullPointerException("tcall must need");
				GenParDiff<T, E, TCall<T, E>> gpf = new GenParDiff<T, E, TCall<T, E>>(id, target, tCall);
				sTaskProcessors.init(gpf);
			} finally {
				r.unlock();
			}
			return sTaskProcessors;
		}
	}

	private <T, E, F> void init(GenParDiff<T, E, F> gen) {
		// TODO Auto-generated method stub
		for (GenParDiff gpd : tCallList) {
			if (gpd.equals(gen)) {
				tCall = (TCall) gpd.getF();
				return;
			}
		}
		tCallList.add(gen);
		tCall = (TCall) gen.getF();
	}

	public <T, E> void reset(Reset<T, E> r) {
		try {
			tCall.reset(r);
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	public <T, E> void register(T i, E e) {
		// TODO Auto-generated method stub
		reset(new Reset<T, E>() {

			@Override
			public T getId() {
				// TODO Auto-generated method stub
				return i;
			}

			@Override
			public E getTarget() {
				// TODO Auto-generated method stub
				return e;
			}

			@Override
			public void end(E e) {
				// TODO Auto-generated method stub

			}
		});
	}

	public <T, E> void submit(Task<T, E> t) {
		try {
			tCall.submit(t);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
